package edu.cmu.cs.stage3.alice.authoringtool.util;

import java.lang.reflect.Method;

import edu.cmu.cs.stage3.alice.authoringtool.AuthoringTool;
import edu.cmu.cs.stage3.alice.authoringtool.editors.questioneditor.QuestionEditor;
import edu.cmu.cs.stage3.alice.authoringtool.editors.responseeditor.ResponseEditor;

public final class EditorUtilities {

 private static Class[] allEditors = {ResponseEditor.class, QuestionEditor.class};

 /**
  * Returns a new Editor instance of the specified Class
  */
 public static edu.cmu.cs.stage3.alice.authoringtool.Editor getEditorFromClass( Class editorClass ) {
  try {
   return (edu.cmu.cs.stage3.alice.authoringtool.Editor)editorClass.newInstance();
  } catch (Throwable t) {
   AuthoringTool.getInstance().showErrorDialog( "Error creating new editor of type " + editorClass, t );
    }
  return null;
  }

 public static java.lang.reflect.Method getSetMethodFromClass (Class editorClass) {
  java.lang.reflect.Method [] methods = editorClass.getMethods();
  //LOB for (Method potentialMethod : methods)
  int t_tam = methods!=null ? methods.length : 0;
  Method potentialMethod = null;
  for (int i_i=0; i_i<t_tam; i_i++) {
   potentialMethod = methods[i_i]; //L
   if (potentialMethod.getName().equals( "setObject" )) {
    Class [] parameterTypes = potentialMethod.getParameterTypes();
    if (parameterTypes.length == 1) {
     if (Object.class.isAssignableFrom( parameterTypes[0] )) {
      return potentialMethod;
      }
     }
    }
   }

  return null;
  }

 public static Class getObjectParameter (Class editorClass) {
  java.lang.reflect.Method setObject = getSetMethodFromClass( editorClass );
  if (setObject != null ) {
   return setObject.getParameterTypes()[0];
   }
  return null;
  }

 /**
  * Returns the Editor type can most suitably view the given objectClass.
  * Suitability is determined by getting the Class hierarchical distance between
  * the given objectClass and the actual type that each Editor's setObject method
  * accepts.
  */
 public static Class getBestEditor (Class objectClass) {
  Class bestEditor = null;
  // System.out.println("src/edu/cmu/cs/stage3/alice/authoringtool/util/EditorUtilities.java: getBestEditor(Class "+objectClass+")");
  // edu.cmu.cs.stage3.alice.authoringtool.editors.responseeditor.ResponseEditor: setObject(edu.cmu.cs.stage3.alice.core.response.UserDefinedResponse)
  // edu.cmu.cs.stage3.alice.authoringtool.editors.questioneditor.QuestionEditor: setObject(edu.cmu.cs.stage3.alice.core.question.userdefined.UserDefinedQuestion)
  int bestDepth = Integer.MAX_VALUE;

  //LOB ''downsize' to become compatible with older Java...'
  //LOB for (Class editorClass : allEditors)
  int t_tam = allEditors!=null ? allEditors.length : 0; //L
  Class editorClass = null;
  for (int i_i=0; i_i<t_tam; i_i++) { //L
   editorClass = allEditors[i_i]; //L
   java.lang.reflect.Method setObject = getSetMethodFromClass(editorClass);
   // System.out.println(" "+allEditors[i_i]+": "+setObject);
   if (setObject != null ) {
    Class [] parameterTypes = setObject.getParameterTypes();
    if (parameterTypes.length == 1) {
     int depth = getObjectClassDepth( parameterTypes[0], objectClass);
     if ((depth < bestDepth) && (depth >= 0) ) {
      bestDepth = depth;
      bestEditor = editorClass;
      }
     }
    }
   }
  return bestEditor;
  }

 // Working area - using src.edu.cmu.cs.stage3.alice.authoringtool.editors.compositeeditor.InsertPanel
 // - 'object' is edu.cmu.cs.stage3.alice.core.response.UserDefinedResponse extends 'DoInOrder' extends 'CompositeResponse'
 public static void editObject (edu.cmu.cs.stage3.alice.authoringtool.Editor editor, Object object) {
  String strObj = edu.cmu.cs.stage3.util.StrUtilities.getComponentName(object),
         strEdit = edu.cmu.cs.stage3.util.StrUtilities.getComponentName(editor);
System.out.println("EditorUtilities.java: editObject(...): editor="+strEdit+" object="+strObj);
  java.lang.reflect.Method setObject = getSetMethodFromClass( editor.getClass() );
  try {
   // Chama indiretamente: edu.cmu.cs.stage3.alice.authoringtool.editors.responseeditor.ResponseEditor.setObject(ResponseEditor.java:31)
   // Chamado: edu.cmu.cs.stage3.alice.authoringtool.TabbedEditorComponent.editObject(TabbedEditorComponent.java:67)
   // edu.cmu.cs.stage3.alice.core.response.UserDefinedResponse object

   //L setObject.invoke( editor, new Object[] { object } ); // ResponseEditor.setObject(edu.cmu.cs.stage3.alice.core.response.UserDefinedResponse toEdit);
   //L Try a direct invocation
   ((edu.cmu.cs.stage3.alice.authoringtool.editors.responseeditor.ResponseEditor)editor).setObject((edu.cmu.cs.stage3.alice.core.response.UserDefinedResponse)object); //L

  } catch (Exception e1) {
   //L Try the old indirect invocation
   System.err.println("Error: EditorUtilities.java: editObject("+strEdit+" ,"+strObj+"): "+e1.toString());
   try {
     setObject.invoke(editor, new Object[]{ object }); // ResponseEditor.setObject(edu.cmu.cs.stage3.alice.core.response.UserDefinedResponse toEdit);
   } catch (Exception e2) {
     System.err.println("Error: EditorUtilities.java: editObject("+strEdit+" ,"+strObj+"): "+e2.toString());
     AuthoringTool.getInstance().showErrorDialog( "Error editing object: " + object, e2 );
     }
   }
  }

 /**
  * Determines how close a subclass is to a superclass
  *
  * @returns  the depth of the class hierarchy between the given superclass and subclass
  */
 private static int getObjectClassDepth (Class superclass, Class subclass) {
  if (! superclass.isAssignableFrom( subclass ) ) {
   return -1;
   }
  Class temp = subclass;
  int i = 0;
  while ( (temp != superclass) && (superclass.isAssignableFrom( temp ) ) ) {
   i++;
   temp = temp.getSuperclass();
   }
  return i;
  }

 }
